﻿#region File Header
//-----------------------------------------------------------------------------
// SibLib
//
// Copyright (C) 2010 Julien Villers
// This program is distributed under the terms of the 
// GNU Lesser General Public License (LGPL).
// See Docs/lgpl.txt and Docs/gpl.txt
//-----------------------------------------------------------------------------
#endregion

using System.Collections.Generic;

namespace SibLib.Containers
{
    /// <summary>
    /// This kind of pool is just a plain pool, storing pre-allocated objects.
    /// </summary>
    /// <typeparam name="T">A class type, with a default constructor required to populate the pool</typeparam>
    public class BasicPool<T> where T: class, new()
    {
        #region Members
        private List<T> m_ListActive;
        private List<T> m_ListAvailable;
        #endregion

        #region Properties
        /// <summary>
        /// Get currently active item count.
        /// </summary>
        public int Count
        {
            get { return m_ListActive.Count; }
        }

        /// <summary>
        /// Get currently available items in pool.
        /// </summary>
        public int Available
        {
            get { return m_ListAvailable.Count; }
        }

        /// <summary>
        /// Get total pool capacity.
        /// </summary>
        public int Capacity
        {
            get { return m_ListActive.Capacity; }       // TODO: support extension?
        }
        #endregion

        #region Constructor

        /// <summary>
        /// Setup a pool with a set capacity.
        /// Will allocate capacity * T items.
        /// </summary>
        /// <param name="capacity">The number of items in the pool</param>
        public BasicPool(int capacity)
        {
            m_ListActive = new List<T>(capacity);
            m_ListAvailable = new List<T>(capacity);

            FillPool();
        }
        #endregion

        private void FillPool()
        {
            for (int i = 0; i != m_ListAvailable.Capacity; i++)
            {
                m_ListAvailable.Add(new T());
            }
        }

        #region Content API

        /// <summary>
        /// Get an item from the pool, add it to active list.
        /// </summary>
        /// <returns>The item if available, null if not.</returns>
        public T AddNewItem()
        {
            if (m_ListAvailable.Count == 0)
                return null;

            T item = m_ListAvailable[0];
            m_ListAvailable.RemoveAt(0);
            m_ListActive.Add(item);
            return item;
        }

        /// <summary>
        /// Restore the item to the pool.
        /// </summary>
        /// <param name="item">An item previously obtained by AddNewItem()</param>
        /// <remarks>This method checks its parameter, if item is not found in active list, nothing will occur.</remarks>
        public void FreeItem(T item)
        {
            if (m_ListActive.Remove(item))
                m_ListAvailable.Add(item);
        }

        /// <summary>
        /// Restore all items to the pool.
        /// </summary>
        public void Clear()
        {
            while (m_ListActive.Count > 0)
            {
                T item = m_ListActive[0];
                m_ListActive.RemoveAt(0);
                m_ListAvailable.Add(item);
            }
        }
        #endregion       
    }
}
